package sample

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"

	"gitee.com/woodpile/utils.log.go"
)

var (
	gopathTmpDir string
)

func init() {
	gopathTmpDir = os.TempDir()
}

//RunSample run sample log message outputting.
func RunSample(index int) {

	RunSampleStaticCall()

	RunSampleWithHandler()

	makeStWithLogger("noNo", 123).RunSampleWithInstanceBondLogger()

	makeStWithLoggerWithRotateFile("noNo", 124, &log.RotateConfig{
		Dir:    os.TempDir(),
		Prefix: fmt.Sprintf("utils.log.sample.%d", index),
		Ext:    "log",

		RotateDuring: 60,
		RotateSize:   64,
	}).RunSampleWithInstanceBondLogger()
}

//ST is a sample struct to show json string printing
type ST struct {
	A string  `json:"a,omitempty"`
	B int64   `json:"b,omitempty"`
	C float64 `json:"c,omitempty"`
	D []byte  `json:"d,omitempty"`
}

//RunSampleStaticCall using static log functions.
func RunSampleStaticCall() {
	//simple log. Z() is necessary in final of every log message calling.
	log.Log().Ctx().P("hello world").Z()
	log.Log().Ctx().PF("i have a %s, is cost $%.2f", "pen", 6.5).Z()
	log.Log().Ctx().P("hello").P("world").P("separate").Z()

	//add global prefix
	log.GlobalHandler().AddPrefix("process", "LogSample")
	log.Log().Ctx().P("with prefix string").Z()

	//use specific log level
	log.WAR().P("A Warning message").Z()
	log.ERR().P("A Error message").Z()

	//set global log level
	log.SetGlobalLevel(log.LvlInfo)
	log.Log().Ctx().P("A Info message").Z()

	//set global log level switch to trace
	log.SetGlobalLevel(log.LvlTrace)

	//use temporary prefix
	log.Log().Ctx().Pre("InTemp").P("with a temporary prefix").Z()
	log.Log().Ctx().P("temporary prefix is gone").Z()
	log.Log().Ctx().P("temporary prefix is always front of message (and format fields)").Pre("Ahead").Z()

	//use format message
	log.Log().Ctx().FS("key", "value").P("with a format field").Z()
	log.Log().Ctx().FI("int", 89).FU("uint", 97).FD("float", 1.3).FX("hex", 0xa4).Z()
	log.Log().Ctx().FS("key", "value").FT("kt", log.FFArrInt64([]int64{123, 321})).P("with a format field").Z()

	{
		st := &ST{A: "abc", B: 123, C: 3.14, D: []byte("---")}
		stBs, _ := json.Marshal(st)
		log.Log().Ctx().FS("key", "value").PF("with a json string param, %v", string(stBs)).Z()
		log.Log().Ctx().FS("key", "value").FS("jsonStr", string(stBs)).P("with a format field json string").Z()
	}

	//set global separator character
	log.GlobalHandler().SetSeparator("^")
	log.Log().Ctx().FS("key", "value").P("with another separator character").Z()

	//recovery
	log.GlobalHandler().SetSeparator("|")

	//use temporary target file
	file, _ := log.MakeTargetFile(gopathTmpDir, "sample.log")
	log.Log().Ctx().Tar(file).FS("key", "value").P("output to stdout and sample.log").Z()

	//use temporary unique target file
	uniqueFile, _ := log.MakeTargetFile(gopathTmpDir, "sample.unique.log")
	log.Log().Ctx().UniTar(uniqueFile).FS("key", "value").P("only output to sample.unique.log").Z()

	//reopen temporary target file
	file.ReopenFile()
	log.Log().Ctx().Tar(file).FS("key", "value").P("output to stdout and sample.log after reopen file").Z()

	//a long continuous call
	log.Log().
		INF().
		Pre("Static").
		Pre("Long").
		FS("user", "woodpile").
		FU("playerID", 93001).
		PF("message in level %v with some parts, err %v", log.GlobalLevel(), nil).
		Z()
}

//RunSampleWithHandler using a log handler.
func RunSampleWithHandler() {
	handler := log.NewHandler()

	//simple log. Z() is necessary in final of every log message calling.
	handler.Ctx().P("hello world").Z()
	handler.Ctx().PF("i have a %s, is cost $%.2f", "pen", 6.5).Z()
	handler.Ctx().P("hello").P("world").P("separate").Z()

	//add prefix
	handler.AddPrefix("process", "LogSample")
	handler.AddPrefix("handler", "new")
	handler.Ctx().P("with prefix string").Z()

	//use specific log level
	handler.WAR().P("A Warning message").Z()
	handler.ERR().P("A Error message").Z()

	//set log level
	handler.SetLevel(log.LvlInfo)
	handler.Ctx().P("A Info message").Z()

	//use temporary prefix
	handler.Ctx().Pre("InTemp").P("with a temporary prefix").Z()
	handler.Ctx().P("temporary prefix is gone").Z()
	handler.Ctx().P("temporary prefix is always front of message (and format fields)").Pre("Ahead").Z()

	//use format message
	handler.Ctx().FS("key", "value").P("with a format field").Z()
	handler.Ctx().FI("int", 89).FU("uint", 97).FD("float", 1.3).FX("hex", 0xa4).Z()
	handler.Ctx().FS("key", "value").FT("kt", log.FFArrInt64([]int64{123, 321})).P("with a format field").Z()

	{
		st := &ST{A: "abc", B: 123, C: 3.14, D: []byte("---")}
		stBs, _ := json.Marshal(st)
		log.Log().Ctx().FS("key", "value").PF("with a json string param, %v", string(stBs)).Z()
		log.Log().Ctx().FS("key", "value").FS("jsonStr", string(stBs)).P("with a format field json string").Z()
	}

	//set handler separator character
	handler.SetSeparator("^")
	handler.Ctx().FS("key", "value").P("with another separator character").Z()

	//recovery
	handler.SetSeparator("|")

	//set code line outputting on
	handler.SwitchCodeLine(true)
	handler.Ctx().FS("key", "value").P("with code line").Z()

	//recovery
	handler.SwitchCodeLine(false)

	//a long continuous call
	handler.INF().
		Pre("Static").
		Pre("Long").
		FS("user", "woodpile").
		FU("playerID", 93001).
		PF("message in level %v with some parts, err %v", handler.Level(), nil).
		Z()
}

type stWithLogger struct {
	log.Logger

	name  string
	index int
}

func makeStWithLogger(n string, i int) *stWithLogger {
	handler := log.NewHandler()
	handler.AddPrefix("ST", "ST.n")
	handler.AddPrefix("Index", "Index."+strconv.Itoa(i))
	return &stWithLogger{
		Logger: handler,
		name:   n,
		index:  i,
	}
}

func makeStWithLoggerWithRotateFile(n string, i int, rc *log.RotateConfig) *stWithLogger {
	handler := log.NewHandler()
	handler.AddPrefix("ST", "ST.n")
	handler.AddPrefix("Index", "Index."+strconv.Itoa(i))

	tf, err := log.MakeTargetFileRotate(rc)
	if nil != err {
		fmt.Printf("!!! Error: %v", err)
		os.Exit(1)
	}
	handler.AddTarget(tf)

	return &stWithLogger{
		Logger: handler,
		name:   n,
		index:  i,
	}
}

func (st *stWithLogger) RunSampleWithInstanceBondLogger() {
	//simple log. Z() is necessary in final of every log message calling.
	st.Ctx().P("hello world").Z()
	st.Ctx().PF("i have a %s, is cost $%.2f", "pen", 6.5).Z()
	st.Ctx().P("hello").P("world").P("separate").Z()

	//add prefix
	st.Ctx().P("can't add prefix string").Z()

	//use specific log level
	st.WAR().P("A Warning message").Z()
	st.ERR().P("A Error message").Z()

	//set log level
	st.Ctx().P("can't set log level").Z()

	//use temporary prefix
	st.Ctx().Pre("InTemp").P("with a temporary prefix").Z()
	st.Ctx().P("temporary prefix is gone").Z()
	st.Ctx().P("temporary prefix is always front of message (and format fields)").Pre("Ahead").Z()

	//use format message
	st.Ctx().FS("key", "value").P("with a format field").Z()
	st.Ctx().FI("int", 89).FU("uint", 97).FD("float", 1.3).FX("hex", 0xa4).Z()
	st.Ctx().FS("key", "value").FT("kt", log.FFArrInt64([]int64{123, 321})).P("with a format field").Z()

	{
		st := &ST{A: "abc", B: 123, C: 3.14, D: []byte("---")}
		stBs, _ := json.Marshal(st)
		log.Log().Ctx().FS("key", "value").PF("with a json string param, %v", string(stBs)).Z()
		log.Log().Ctx().FS("key", "value").FS("jsonStr", string(stBs)).P("with a format field json string").Z()
	}

	//set handler separator character
	st.Ctx().FS("key", "value").P("can't set separator character").Z()

	//a long continuous call
	st.INF().
		Pre("Static").
		Pre("Long").
		FS("user", "woodpile").
		FU("playerID", 93001).
		PF("message in level %v with some parts, err %v", "can't get level", nil).
		Z()
}
